package utils

import (
	"path/filepath"
	"strings"
	"regexp"
)

// SafePath 安全路径检查
func SafePath(basePath, userPath string) (string, bool) {
	if userPath == "" {
		return basePath, true
	}

	// 首先检查用户路径是否有效
	if !IsValidPath(userPath) {
		return "", false
	}

	// 清理路径，移除相对路径组件
	cleanPath := filepath.Clean(userPath)
	
	// 检查各种路径遍历攻击模式
	if strings.HasPrefix(cleanPath, "..") || 
	   strings.Contains(cleanPath, "../") ||
	   strings.Contains(cleanPath, "..\\") ||
	   strings.HasPrefix(cleanPath, "/") ||
	   strings.Contains(cleanPath, "://") {
		return "", false
	}

	// 检查是否包含空字符或其他控制字符
	for _, b := range []byte(cleanPath) {
		if b < 32 && b != 9 && b != 10 && b != 13 { // 允许tab, lf, cr
			return "", false
		}
	}

	fullPath := filepath.Join(basePath, cleanPath)
	
	// 确保路径在基础目录内 - 双重检查
	absBase, err1 := filepath.Abs(basePath)
	absFull, err2 := filepath.Abs(fullPath)
	
	if err1 != nil || err2 != nil {
		return "", false
	}
	
	// 标准化路径分隔符
	absBase = filepath.Clean(absBase)
	absFull = filepath.Clean(absFull)
	
	// 确保完整路径确实在基础目录内
	if !strings.HasPrefix(absFull, absBase) {
		return "", false
	}
	
	// 额外检查：确保不是基础目录本身的父目录
	if len(absFull) < len(absBase) {
		return "", false
	}

	return fullPath, true
}

// SanitizeFilename 清理文件名，移除危险字符
func SanitizeFilename(filename string) string {
	// 如果文件名为空，返回默认名称
	if filename == "" {
		return "unnamed_file"
	}
	
	// 移除路径分隔符和相对路径组件
	filename = strings.ReplaceAll(filename, "/", "_")
	filename = strings.ReplaceAll(filename, "\\", "_")
	filename = strings.ReplaceAll(filename, "..", "_")
	
	// 移除控制字符和其他危险字符
	re := regexp.MustCompile(`[<>:"|?*\x00-\x1f\x7f]`)
	filename = re.ReplaceAllString(filename, "_")
	
	// 移除开头的点号(隐藏文件)和空格
	filename = strings.TrimLeft(filename, ". ")
	
	// 移除结尾的点号和空格
	filename = strings.TrimRight(filename, ". ")
	
	// 如果清理后文件名为空，返回默认名称
	if filename == "" {
		return "unnamed_file"
	}
	
	// 限制文件名长度(Windows路径限制)
	if len(filename) > 255 {
		ext := filepath.Ext(filename)
		base := filename[:255-len(ext)]
		filename = base + ext
	}
	
	return filename
}

// IsValidPath 检查路径是否安全
func IsValidPath(userPath string) bool {
	// 检查是否包含危险的路径遍历字符
	if strings.Contains(userPath, "..") {
		return false
	}
	
	// 检查是否包含绝对路径字符
	if strings.HasPrefix(userPath, "/") || strings.Contains(userPath, ":") {
		return false
	}
	
	// 检查是否包含危险字符
	dangerousChars := []string{"<", ">", "|", "?", "*", "\x00"}
	for _, char := range dangerousChars {
		if strings.Contains(userPath, char) {
			return false
		}
	}
	
	return true
} 